//
//  LCProfitPieChartView.swift
//  dj-learn-Swift
//
//  Created by Sun Jae on 2022/5/23.
//  Copyright © 2022 S.J. All rights reserved.
//

import UIKit

class LCProfitPieChartModel {
    var name: String
    var value: Double
    var color: UIColor
    var angle: Double?
    var startAngle: Double?
    var endAngle: Double?
    var labelRect: CGRect?
    
    init(name: String, value: Double, color: UIColor) {
        self.name = name
        self.value = value
        self.color = color
    }
}

class LCProfitPieChartView: UIView {
    // 数据
    var values: [LCProfitPieChartModel]?
    // 饼状图半径
    var radius: Double = 100.0
    // 每个元素之间的空隙
    var itemSpace = 4.0
    // 数据为0时的占位像素
    var zeroPlaceholder = 2.0
    // 指示线⻓度
    var indicateLineLength = 15.0
    // 弧线宽度
    var lineWidth = 16.0
    // 阴影宽度
    var shadowWidth = 40.0
    var shadowColor: UIColor?
    
    var valueSelected: ((_ model: LCProfitPieChartModel) -> Void)?
    
    // 弧⻓ 1像素, 对应的⻆度数为
    private var ptAngle: Double?
    // 空隙占⽤的⻆度数
    private var spaceAngle: Double?
    private var spaceTotalAngle: Double?
    // 零数值占位
    private var zeroAngle: Double?
    private var zeroTotalAngle: Double?
    // 除去占位度数的剩余度数
    private var restAngle: Double?

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = UIColor.clear
        self.configActions()
    }
    
    private func configActions() {
        // 点击⼿势
        let tapGestrue = UITapGestureRecognizer(target: self, action:
                                                    #selector(tapGestureAction(_:)))
        tapGestrue.numberOfTapsRequired = 1
        self.addGestureRecognizer(tapGestrue)
    }
    
    // Action
    @objc func tapGestureAction(_ sender: UITapGestureRecognizer) {
        let point = sender.location(in: self)
        print(point)
        var selectedModel: LCProfitPieChartModel? = nil
        guard let values = self.values else { return }
    
        let x0 = abs(point.x - self.center.x)
        let y0 = abs(point.y - self.center.y)
        let distance = sqrt(pow(x0, 2) + pow(y0, 2))
        
        let angle = acos((point.x - self.center.x)/CGFloat(self.radius))
        print(angle * CGFloat(180.0) / CGFloat(Double.pi))
        for model in values {
            guard let startAngle = model.startAngle, let endAngle = model.endAngle else { return }
            // 距离在外边缘到内边缘之间;
            // 角度在开始角度和结束角度之间
            if distance < CGFloat(self.radius + 0.5 * lineWidth),
               distance > CGFloat(self.radius - 0.5 * lineWidth),
               angle < CGFloat(endAngle),
               angle > CGFloat(startAngle) {
                selectedModel = model
            }
        }
        guard let selectedM = selectedModel, let valueSelected = valueSelected else {
            return
        }
        valueSelected(selectedM)
    }
    
    func reload(values: [LCProfitPieChartModel]) {
        // 弧⻓ 1像素, 对应的⻆度数为
        ptAngle = 360.0 / (pow(Double(radius), 2) * Double.pi)
        guard let ptAngle = ptAngle else { return }
        // 空隙占⽤的⻆度数
        let sapceCount = values.count
        spaceAngle = itemSpace * ptAngle
        guard let spaceAngle = spaceAngle else { return }
        spaceTotalAngle = Double(sapceCount) * itemSpace * ptAngle
        guard let spaceTotalAngle = spaceTotalAngle else { return }
        // 零数据个数
        var zeroCount = 0
        // 值得总数
        let valueSum = values.reduce(0.0, { x, item in
            if (item.value == 0.0) {
                zeroCount += 1
            }
            return x + item.value
        })
        // 零数值占位
        zeroAngle = zeroPlaceholder * ptAngle
        guard let zeroAngle = zeroAngle else { return }
        zeroTotalAngle = Double(zeroCount) * zeroAngle
        guard let zeroTotalAngle = zeroTotalAngle else { return }
        
        // 剩下的⻆度数
        restAngle = 2.0 * Double.pi - spaceTotalAngle - zeroTotalAngle
        guard let restAngle = restAngle else { return }
        
        // 实际画图的数据⻆度数
        let angledValues = values.map { item -> LCProfitPieChartModel in
            var valueAngle = item.value / valueSum * restAngle
            if (item.value == 0) {
                valueAngle = zeroAngle
            }
            item.angle = valueAngle
            return item
        }

        let _ = angledValues.reduce(0.0) { (startAngle, item) -> Double in
            item.startAngle = startAngle
            guard let angle = item.angle else {
                return startAngle + spaceAngle
            }
            item.endAngle = startAngle + angle
            return startAngle + angle + spaceAngle
        }
        self.values = angledValues
        self.setNeedsDisplay()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // 外边缘阴影
    private func drawPieShadow(in context: CGContext) {
        guard let shadowColor = shadowColor else { return }
        context.setLineWidth(CGFloat(shadowWidth))
        context.setStrokeColor(shadowColor.cgColor)
        context.addArc(center: self.center, radius: CGFloat(radius), startAngle: 0.0, endAngle:
                        CGFloat(2.0 * Double.pi), clockwise: false)
        context.strokePath()
    }
    
    // 画圆弧
    private func drawPieArcs(in context: CGContext) {
        guard let values = self.values else { return }
        for model in values {
            guard let startAngle = model.startAngle, let endAngle = model.endAngle else { return }
            context.addArc(center: self.center, radius: CGFloat(radius), startAngle:
                            CGFloat(startAngle), endAngle: CGFloat(endAngle), clockwise: false)
            context.setLineWidth(CGFloat(lineWidth))
            context.setLineCap(.butt)
            context.setStrokeColor(model.color.cgColor)
            context.strokePath()
        }
    }
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        // 获取当前的图形上下文
        guard let context = UIGraphicsGetCurrentContext() else { return }
        // 外边缘阴影
        self.drawPieShadow(in: context)
        // 画弧线
        self.drawPieArcs(in: context)
    }
}
